package com.pms.platform.resource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;




public class ResourceManager
{
	/** The number of connections passed to a thread and not yet released */
	protected volatile int  mNumberOfConnectionsInUse = 0;
	protected volatile long mLastTraceTimeForNumberOfConnectionsInUse = 0;
	public static Properties properties = new Properties();
	private static final String TRACE_ID = "ResourceManager";

	private DataSource ds = null;

	private boolean isStandAlone = false;
	private DbConnectionBroker myBroker = null;
	String resourcePath=null;
	private void init() throws Exception 
	{

		Context ctx = new InitialContext();
		ds = (DataSource) ctx.lookup("java:comp/env/jdbc/splash");

		ctx.close();

	}

	private void initStandAlone() throws FileNotFoundException, IOException {
		isStandAlone = true;


		/*
		 * Unix path
		 * 
		 */

		//resourcePath=System.getenv("TRAVIS_HOME");
		//properties.load(new FileInputStream(new File(resourcePath)));

		//end  Unix path

		String userdir= System.getProperty("user.dir");
		System.out.println("Current Directory : "+ userdir);

		properties.load(new FileInputStream(new File(userdir+"\\splash.properties")));

		System.out.println("----- > Initializing Resource Manger ");

		myBroker = new DbConnectionBroker(properties.getProperty("javax.jdo.option.ConnectionDriverName"),
				properties.getProperty("javax.jdo.option.ConnectionURL"),
				properties.getProperty("javax.jdo.option.ConnectionUserName"),
				properties.getProperty("javax.jdo.option.ConnectionPassword"),25,50,
				"SplashStandAlone.log",1.0);

	}

	/** Get a database connection from the pool
	 *
	 * @exception SQLException     If a connection cannot be acquired
	 *
	 * Connection has AutoCommit <b>enabled</b> by default.
	 *
	 **/
	protected Connection getConnectionInternal() throws SQLException {
		return getConnectionInternal(true);
	}

	protected Connection getConnectionInternal(String mClassName) throws SQLException {
		return getConnectionInternal(true, mClassName);
	}


	/** Get a database connection from the pool
	 *
	 * @param aAutoCommit   True if auto-commit is required
	 *
	 * @exception SQLException     If a connection cannot be acquired
	 *
	 **/
	protected Connection getConnectionInternal(boolean aAutoCommit) throws SQLException {

		Connection connection = null;
		try {
			if(!isStandAlone) {
				connection=this.ds.getConnection();
			} else {
				connection=myBroker.getConnection();
			}

			// By default, enable auto-committing of transactions
			connection.setAutoCommit(aAutoCommit);
			connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 
		}
		// Keep a record of the failed connection request
		catch (SQLException e) {
			throw e;
		}

		// increment the global count of connections in use
		synchronized(this) {
			mNumberOfConnectionsInUse++;
		}

		System.out.println("JDBC Connections in use " + mNumberOfConnectionsInUse);

		return connection;
	}	

	protected Connection getConnectionInternal(boolean aAutoCommit, String mClassName) throws SQLException {

		Connection connection = null;
		try {
			if(!isStandAlone) {
				connection=this.ds.getConnection();
			} else {
				connection=myBroker.getConnection();
			}

			// By default, enable auto-committing of transactions
			connection.setAutoCommit(aAutoCommit);
			connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 
		}
		// Keep a record of the failed connection request
		catch (SQLException e) {
			throw e;
		}

		// increment the global count of connections in use
		synchronized(this) {
			mNumberOfConnectionsInUse++;
		}

		System.out.println("Class - " + mClassName + "JDBC Connections in use " + mNumberOfConnectionsInUse);

		return connection;
	}	


	/** Return a database connection to the pool
	 *
	 * @param aConnection   Connection
	 *
	 */
	protected void freeConnectionInternal(Connection aConnection,String trace) {

		try {

			// Close the connection, for convenience we allow the connection to be null
			if (aConnection!=null) {

				synchronized(this) {
					mNumberOfConnectionsInUse--;
				}

				// Check if the autocommit was enabled         

				if(!isStandAlone) {
					aConnection.close();
				} else {
					String respStr=	myBroker.freeConnection(aConnection);
					if(respStr== null){
						System.out.println("! "+trace+" Connection is not closed ");
					}else{
						System.out.println("@@  "+trace+" Connection is closed");
					}
				}
			}
		}
		// Do not throw exception
		catch (SQLException e) {
			System.out.println(e);
			System.out.println("freeConnection() failed");
		}
	}	

	protected void close(Connection conn)
	{
		try {
			if (conn != null) conn.close();
		}
		catch (SQLException sqle)
		{
			sqle.printStackTrace();
		}
	}

	public static void close(PreparedStatement stmt)
	{
		try {
			if (stmt != null) stmt.close();
		}
		catch (SQLException sqle)
		{
			sqle.printStackTrace();
		}
	}

	public static void close(ResultSet rs)
	{
		try {
			if (rs != null) rs.close();
		}
		catch (SQLException sqle)
		{
			sqle.printStackTrace();
		}

	}


	/** Singleton Instance */
	private static ResourceManager mInstance=null;

	/** Return true if the connection manager is initialised */
	public static boolean isInitialised() {
		return mInstance!=null;
	}

	/** Return the current instance
	 *
	 * @exception BobeException     If the connection manager is not configured
	 *
	 */
	public static ResourceManager getInstance() {

		if (mInstance==null) {
			mInstance = new ResourceManager();

			try{
				mInstance.init();
			}catch(Exception e){
				try {
					mInstance.initStandAlone();
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}  
			}

		}

		return mInstance;
	}


	/** Get a database connection from the pool
	 *
	 * @exception SQLException     If a connection cannot be acquired
	 *
	 * Connection has AutoCommit <b>enabled</b> by default.
	 *
	 **/
	public static Connection getConnection() throws SQLException {
		return getInstance().getConnectionInternal();
	}

	/** Get a database connection from the pool
	 *
	 * @exception SQLException     If a connection cannot be acquired
	 *
	 * Connection has AutoCommit <b>enabled</b> by default.
	 *
	 **/
	public static Connection getConnection(String mClassName) throws SQLException {
		return getInstance().getConnectionInternal(mClassName);
	}


	/** Get a database connection from the pool
	 *
	 * @param aAutoCommit   True if auto-commit is required
	 *
	 * @exception SQLException     If a connection cannot be acquired
	 *
	 **/
	public static Connection getConnection(boolean aAutoCommit) throws SQLException {
		return getInstance().getConnectionInternal(aAutoCommit);
	}

	public static Connection getConnection(boolean aAutoCommit, String mClassName) throws SQLException {
		return getInstance().getConnectionInternal(aAutoCommit, mClassName);
	}


	public static void freeConnection() {
		synchronized(getInstance()) {
			getInstance().mNumberOfConnectionsInUse--;
		}
	}


	/** Return a database connection to the pool
	 *
	 * @param aConnection   Connection
	 *
	 */
	public static void freeConnection(Connection aConnection,String trace) {
		getInstance().freeConnectionInternal(aConnection ,trace);
	}

	/** Returns the number of JDBC connections that have been given by the manager
	 * and not yet returned to the manager.
	 *
	 * @return int
	 */
	public static int getNumberOfConnectionsInUse() {
		return getInstance().mNumberOfConnectionsInUse;
	}   
}
